package com.hengpeng.itfin.service.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.hengpeng.common.exception.ServiceResult;
import com.hengpeng.common.exception.SystemException;
import com.hengpeng.common.persist.entity.AbstractEntity.BoolValue;
import com.hengpeng.common.util.DateTimeUtil;
import com.hengpeng.common.util.MoneyUtil;
import com.hengpeng.common.util.StringHelper;
import com.hengpeng.itfin.common.SystemConfigUtil;
import com.hengpeng.itfin.service.BorrowService;
import com.hengpeng.itfin.tools.InvestUtils;
import com.hengpeng.itfin.tools.StringUtils;
import com.hengpeng.itfinbase.constants.RespCodeConstants;
import com.hengpeng.itfinbase.constants.RespCodeConstants.BorrowInfoCode;
import com.hengpeng.itfinbase.constants.RespCodeConstants.CommonCode;
import com.hengpeng.itfinbase.constants.TransCodeConstants;
import com.hengpeng.itfinbase.en.SubAccountType;
import com.hengpeng.itfinbase.idAssign.ID;
import com.hengpeng.itfinbase.message.RequestMessage;
import com.hengpeng.itfinbase.message.ResponseMessage;
import com.hengpeng.itfinbase.message.partner.AddBidInfoRequest;
import com.hengpeng.itfinbase.message.partner.LoansRequest;
import com.hengpeng.itfinbase.message.partner.LoansResponse;
import com.hengpeng.itfinbase.message.partner.PartnerTransType;
import com.hengpeng.itfinbase.message.partner.ReconciliationRequestMsg;
import com.hengpeng.itfinbase.message.partner.ReconciliationResponseMsg;
import com.hengpeng.itfinbase.message.partner.ReconciliationResponseMsg.ReconciliationInfo;
import com.hengpeng.itfinbase.message.partner.UsrUnFreezeRequest;
import com.hengpeng.itfinbase.message.partner.UsrUnFreezeResponse;
import com.hengpeng.itfinbase.persist.Account;
import com.hengpeng.itfinbase.persist.AccountLog.TradeMode;
import com.hengpeng.itfinbase.persist.AccountLog.TransType;
import com.hengpeng.itfinbase.persist.BorrowInfo;
import com.hengpeng.itfinbase.persist.BorrowInfo.BorrowStatus;
import com.hengpeng.itfinbase.persist.BorrowInfo.DurationType;
import com.hengpeng.itfinbase.persist.BorrowInfo.InputStatus;
import com.hengpeng.itfinbase.persist.InvestInfo;
import com.hengpeng.itfinbase.persist.InvestInfo.InvestStatus;
import com.hengpeng.itfinbase.persist.Partner;
import com.hengpeng.itfinbase.persist.ReceivePlan;
import com.hengpeng.itfinbase.persist.ReceivePlan.ReceiveStatus;
import com.hengpeng.itfinbase.persist.RepaymentPlan;
import com.hengpeng.itfinbase.persist.RepaymentPlan.ReplaymentStatus;

@Service
@Lazy
public class BorrowServiceImpl extends BaseServiceImpl implements BorrowService
{
	public static Log logger = LogFactory.getLog(BorrowServiceImpl.class);

	private final static ExecutorService execute = Executors.newCachedThreadPool();

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void borrowStartRaise()
	{
		List<BorrowInfo> list = daoFactory.getBorrowInfoDao().lockScheduleList();
		for (BorrowInfo borrowInfo : list)
		{
			borrowInfo.setStatus(BorrowStatus.RAISE);
			borrowInfo.setUpdateTime(new Date());
		}
		daoFactory.getBorrowInfoDao().updateList(list);
		logger.info("已处理" + list.size() + "条标的为募集中");
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void borrowEndRaise()
	{
		List<BorrowInfo> list = daoFactory.getBorrowInfoDao().endRaistList();
		for (BorrowInfo borrowInfo : list)
		{
			borrowInfo.setStatus(BorrowStatus.END);
			borrowInfo.setUpdateTime(new Date());
		}
		daoFactory.getBorrowInfoDao().updateList(list);
		logger.info("已处理" + list.size() + "条标的为募集结束");
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED)
	public void overdure()
	{
		List<RepaymentPlan> plans = daoFactory.getRepaymentPlanDao().getOverdureList();
		for (RepaymentPlan plan : plans)
		{
			plan.setIsOverDured(BoolValue.YES);
			plan.setOverdueDate(DateTimeUtil.addDate(plan.getLastRepayDate(), 1));
			plan.setUpdateTime(new Date());
		}
		daoFactory.getRepaymentPlanDao().updatePlans(plans);
	}

	@Override
	public void addBidInfoList()
	{
		List<BorrowInfo> infoList = daoFactory.getBorrowInfoDao().getUnAddBidList();
		for (BorrowInfo borrow : infoList)
		{
			AddBidInfoRequest addRequest = new AddBidInfoRequest();
			addRequest.setPartnerTransType(PartnerTransType.AddBidInfo);
			addRequest.setProId(borrow.getId().toString());
			addRequest.setBidStartDate(StringHelper.getStringFromDate(borrow.getBidOpenTime(), "yyyyMMddhhmmss"));
			addRequest.setBidEndDate(StringHelper.getStringFromDate(borrow.getBidStopTime(), "yyyyMMddhhmmss"));
			addRequest.setBorrCustId(borrow.getBorrowUserTrustAccountId());
			addRequest.setBorrTotAmt(MoneyUtil.convertFenToYuan(borrow.getBorrowMoney()));
			addRequest.setYearRate(new DecimalFormat("#.00").format((borrow.getBorrowRate() + borrow.getRewardRate())));
			addRequest.setGuarCompId(borrow.getGuaranteeUserTrustAccountId());
			Double guarAmt = borrow.getBorrowMoney() * borrow.getGuaranteeFeeRate() / 100;// 担保费用
			addRequest.setGuarAmt(MoneyUtil.convertFenToYuan(guarAmt.longValue()));
			addRequest.setProArea("4402");
			Date end = null;
			switch (borrow.getRepaymentType())
			{
				case EQUALINTEREST:// 等额本息
					long month = InvestUtils.equalInterest(borrow.getBorrowMoney(),
							(borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration());
					end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
					addRequest.setRetAmt(MoneyUtil.convertFenToYuan(month * borrow.getBorrowDuration()));
					addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
					addRequest.setRetType("01");
					break;
				case EQUALPRINCIPAL:// 等额本金
					long total = InvestUtils.equalPrincipal(borrow.getBorrowMoney(),
							(borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration());// 等额本金还款总额
					end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
					addRequest.setRetAmt(MoneyUtil.convertFenToYuan(total));
					addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
					addRequest.setRetType("02");
					break;
				case MONTHINTEREST:// 按月付息到期还本
					if (borrow.getDurType().equals(DurationType.MONTH))
					{
						end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
					}
					else
					{
						end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.DATE);
					}
					long interest = InvestUtils.rtcapitalInterest(borrow.getBorrowMoney(),
							(borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration(),
							borrow.getDurType());
					addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
					addRequest.setRetAmt(MoneyUtil.convertFenToYuan(interest + borrow.getBorrowMoney()));
					addRequest.setRetType("03");
					break;
				case RTCAPITALINTEREST:// 一次性还本付息
					if (borrow.getDurType().equals(DurationType.MONTH))
					{
						end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.MONTH);
					}
					else
					{
						end = StringUtils.addTime(borrow.getBidStopTime(), borrow.getBorrowDuration(), Calendar.DATE);
					}
					long rest = InvestUtils.rtcapitalInterest(borrow.getBorrowMoney(),
							(borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration(),
							borrow.getDurType());
					addRequest.setRetDate(StringHelper.getStringFromDate(end, "yyyyMMdd"));
					addRequest.setRetAmt(MoneyUtil.convertFenToYuan(rest + borrow.getBorrowMoney()));
					addRequest.setRetType("04");
					break;
			}
			serviceFactory.getBorrowService().addBidInfo(addRequest);
		}
	}

	@Override
	@Transactional(propagation = Propagation.NEVER)
	public ServiceResult<Boolean> loans(LoansRequest request)
	{
		final BorrowInfo borrow = daoFactory.getBorrowInfoDao().get(request.getBorrowId());
		serviceFactory.getBorrowService().makeReceivePlans(borrow);// 生成收款计划
		serviceFactory.getBorrowService().makeRepayPlans(borrow.getId());// 生成还款计划
		execute.execute(new Runnable()
		{
			public void run()
			{
				serviceFactory.getBorrowService().loansParnter(borrow);
			}
		});// 后台放款操作
		return new ServiceResult<Boolean>();
	}

	@Override
	public ServiceResult<Boolean> loss(UsrUnFreezeRequest request)
	{
		BorrowInfo borrow = daoFactory.getBorrowInfoDao().get(request.getBorrowId());
		List<InvestInfo> investList = daoFactory.getInvestInfoDao().queryList(borrow.getId(),
				new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.CANCLING });
		if (investList != null && investList.size() > 0)
		{
			borrow.setStatus(BorrowStatus.LOSSING);
			serviceFactory.getPersistService().update(borrow);
			for (InvestInfo invest : investList)
			{
				if (invest.getStatus().equals(InvestStatus.CANCLING) || invest.getStatus().equals(InvestStatus.SUCESS))
				{
					UsrUnFreezeRequest free = serviceFactory.getBorrowService().loss(invest);
					UsrUnFreezeResponse response = (UsrUnFreezeResponse) serviceFactory.getPartnerService().request(
							free);
					serviceFactory.getBorrowService().lossResponse(response);
				}
			}
		}

		return new ServiceResult<Boolean>();
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public UsrUnFreezeRequest loss(InvestInfo invest)
	{
		InvestInfo info = daoFactory.getInvestInfoDao().lockById(invest.getId());
		String unFreeOrderId = ID.getInstanse().getID(18).toString();
		UsrUnFreezeRequest request = new UsrUnFreezeRequest();
		request.setOrdId(unFreeOrderId);
		request.setOrdDate(StringHelper.getStringFromDate(new Date(), "yyyyMMdd"));
		request.setTrxId(invest.getFreezeTrxId());
		request.setPartnerTransType(PartnerTransType.UsrUnFreeze);
		info.setStatus(InvestStatus.CANCLING);
		info.setUpdateTime(new Date());
		info.setUnFreeOderId(unFreeOrderId);
		daoFactory.getInvestInfoDao().update(info);
		return request;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public ServiceResult<String> lossResponse(UsrUnFreezeResponse response)
	{
		ServiceResult<String> result = new ServiceResult<String>();
		if (RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode()))
		{
			InvestInfo investInfo = serviceFactory.getInvestInfoService().getInvestByUnFreeOrderId(response.getOrdId(),
					true);
			if (investInfo != null && investInfo.getStatus().equals(InvestStatus.CANCLING))
			{
				investInfo.setStatus(InvestStatus.CANCLED);
				investInfo.setCancelTime(new Date());
				daoFactory.getInvestInfoDao().update(investInfo);
				serviceFactory.getAccountService().changeAccountMoney(investInfo.getInvestUserId(),
						investInfo.getInvestMoney(), null, null, TransType.CANCLE, TradeMode.UNFREEZE,
						investInfo.getId().toString(), "标的撤标解冻:" + investInfo.getBorrowName());// 投资人解冻
				// 判断投标记录是否都已撤标,如果都已撤标则将借款标的状态改为:已流标
				Long count = daoFactory.getInvestInfoDao().countByBorrowId(investInfo.getBorrowInfoId(),
						new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.CANCLING });
				if (count == 0)
				{
					BorrowInfo borrow = daoFactory.getBorrowInfoDao().lockById(investInfo.getBorrowInfoId());
					borrow.setStatus(BorrowStatus.LOSSED);
					daoFactory.getBorrowInfoDao().update(borrow);
				}
				result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
				result.setMessage(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
				result.setIsSuccess(true);
			}
			else
			{
				result.setCode(RespCodeConstants.InvestCode.INVEST_UNKONW);
				result.setMessage(RespCodeConstants.InvestCode.INVEST_UNKONW_MSG);
				result.setIsSuccess(false);
			}
		}
		return result;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public ServiceResult<String> loansResponse(LoansResponse response)
	{
		ServiceResult<String> result = new ServiceResult<String>();
		if (RespCodeConstants.CommonCode.TRANS_SUC.equals(response.getRespCode())
				|| RespCodeConstants.BorrowInfoCode.TRANSMESSAGE_ERRCODE_LOANED.equals(response.getRespCode()))
		{
			InvestInfo investInfo = serviceFactory.getDaoFactory().getInvestInfoDao()
					.lockById(Long.parseLong(response.getOrdId()));
			if (investInfo != null && investInfo.getStatus().equals(InvestStatus.LOANING))
			{
				ReceivePlan plan = daoFactory.getStaticJDBCDao().getTotleReceive(investInfo.getId(),
						investInfo.getInvestUserId());
				Long recBaseMoney = plan.getRecBaseMoney();
				Long recInterestMoney = plan.getRecInterestMoney();
				Long recAddMoney = plan.getRecAddMoney();
				investInfo.setStatus(InvestStatus.LOANED);
				serviceFactory.getPersistService().update(investInfo);
				BorrowInfo borrow = serviceFactory.getDaoFactory().getBorrowInfoDao().get(investInfo.getBorrowInfoId());
				Long guaFee = InvestUtils.accuracy(investInfo.getInvestMoney() * borrow.getGuaranteeFeeRate() / 100);// 保证金费率
				Long fee = InvestUtils.accuracy(investInfo.getInvestMoney() * borrow.getBorrowFeeRate() / 100);// 平台佣金
				Long borrowMoney = investInfo.getInvestMoney() - guaFee;// 借款人应收金额

				serviceFactory.getAccountService().changeAccountMoney(investInfo.getInvestUserId(),
						investInfo.getInvestMoney(), TransType.LOAN, TradeMode.UNFREEZE, investInfo.getId().toString(),
						"标的投资放款:" + borrow.getBorrowName() + ",解冻");// 投资先解冻

				serviceFactory.getAccountService().loansChangeAccountMoney(investInfo.getInvestUserId(),
						investInfo.getInvestMoney(), recBaseMoney, (recInterestMoney + recAddMoney), TransType.LOAN,
						TradeMode.SUBTRACT, investInfo.getId().toString(), "标的投资放款转出:" + borrow.getBorrowName(), true);// 投资人放款转出

				// 托管模式情况下，分批给借款用户加款
				if (serviceFactory.getPartnerService().isTrustPattern())
				{
					serviceFactory.getAccountService().add(borrow.getGuaranteeUserId(), TransType.LOAN_GUAR, guaFee,
							investInfo.getId().toString(), "标的保证金放款收入:" + borrow.getBorrowName());// 保证金费率增加

					serviceFactory.getAccountService().loansChangeAccountMoney(borrow.getBorrowUserId(), borrowMoney,
							recBaseMoney, recInterestMoney, TransType.LOAN, TradeMode.ADD,
							investInfo.getId().toString(), "标的借款放款收入:" + borrow.getBorrowName(), true);// 借款人收入借款金额

					serviceFactory.getAccountService().subtractNoFreeze(borrow.getBorrowUserId(), TransType.LOAN_FEE,
							fee, borrow.getId().toString(), "标的放款服务费扣款:" + borrow.getBorrowName());// 借款用户扣服务费证金
				}

				result.setCode(RespCodeConstants.CommonCode.TRANS_SUC);
				result.setMessage("处理成功!");
				result.setIsSuccess(true);
			}
			else
			{
				result.setCode("");
				result.setMessage("投资信息不存在或已经放款成功了");
				result.setIsSuccess(false);
			}
		}
		return result;
	}

	@Override
	public void loansParnter(BorrowInfo borrow)
	{
		List<InvestInfo> investList = daoFactory.getInvestInfoDao().queryList(borrow.getId(),
				new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.LOANING });
		for (InvestInfo invest : investList)
		{
			if (!invest.getStatus().equals(InvestStatus.LOANED))
			{
				LoansRequest request = serviceFactory.getBorrowService().loansInvest(borrow, invest);
				LoansResponse response = (LoansResponse) serviceFactory.getPartnerService().request(request);
				serviceFactory.getBorrowService().loansResponse(response);// 调用放款接口返回操作
			}
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public LoansRequest loansInvest(BorrowInfo borrow, InvestInfo invest)
	{
		InvestInfo info = daoFactory.getInvestInfoDao().lockById(invest.getId());
		LoansRequest request = new LoansRequest();
		request.setOrdId(info.getId().toString());
		request.setOrdDate(StringHelper.getStringFromDate(new Date(), "yyyyMMdd"));
		request.setOutCustId(info.getInvestUserTrustAccountId());
		
		Long guarantFee = InvestUtils.accuracy(info.getInvestMoney() * borrow.getGuaranteeFeeRate() / 100);// 担保手续费
		Long fee = InvestUtils.accuracy(info.getInvestMoney() * borrow.getBorrowFeeRate() / 100);// 平台佣金

		request.setTransAmt(MoneyUtil.convertFenToYuan(info.getInvestMoney() - fee  - guarantFee));
		request.setFee(MoneyUtil.convertFenToYuan(InvestUtils.accuracy(fee + guarantFee)));
		request.setSubOrdId(info.getId().toString());
		request.setSubOrdDate(StringHelper.getStringFromDate(info.getInvestTime(), "yyyyMMdd"));
		request.setInCustId(borrow.getBorrowUserTrustAccountId());
		request.setFeeObjFlag("O");
		request.setIsDefault("N");
		request.setIsUnFreeze("Y");
		request.setReqExt("{\"ProId\":\"" + borrow.getId() + "\"}");
		request.setFreezeTrxId(info.getFreezeTrxId());// 获取投标时汇付返回的冻结标识
		/** 生成解冻订单号 */
		String unFreezeOrdId = ID.getInstanse().getID(18).toString();
		request.setUnFreezeOrdId(unFreezeOrdId);
		info.setUnFreeOderId(unFreezeOrdId);

		request.setProId(borrow.getId().toString());
		request.setPartnerTransType(PartnerTransType.Loans);
		String partnerId = SystemConfigUtil.getConfigValue("partner.id");
		Partner partner = daoFactory.getPartnerDao().get(partnerId);
		String subAccountId = partner.getExtConfigs().get(SubAccountType.SPEDT.toString());
		Account guar = serviceFactory.getAccountService().getAccount(borrow.getGuaranteeUserId());
		if (guar == null)
		{
			throw new SystemException("放款失败，担保用户不存在:" + borrow.getGuaranteeUserId());
		}
		/**
		 * <pre>
		 * 分账：
		 * (1)平台收取借款服务费
		 * (2)担保人收取担保费
		 * (3)手续费从借款人账户中扣取
		 * </pre>
		 */
		StringBuffer divDetails = new StringBuffer("[");
		divDetails.append("{\"DivCustId\":\"" + partner.getMerchantId() + "\",\"DivAcctId\":\"" + subAccountId
				+ "\",\"DivAmt\":\""
				+ MoneyUtil.convertFenToYuan(fee) + "\"},");
		
		divDetails.append("{\"DivCustId\":\"" + guar.getTrustAccountId() + "\",\"DivAcctId\":\""
				+ guar.getSubAccountId() + "\",\"DivAmt\":\""
				+ MoneyUtil.convertFenToYuan(InvestUtils.accuracy(guarantFee)) + "\"}]");
		
		request.setDivDetails(divDetails.toString());
		info.setStatus(InvestStatus.LOANING);
		info.setLoanTime(new Date());
		daoFactory.getInvestInfoDao().update(info);
		return request;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void makeRepayPlans(Long id)
	{
		BorrowInfo info = daoFactory.getBorrowInfoDao().lockById(id);
		List<RepaymentPlan> plans = new ArrayList<RepaymentPlan>();
		if (info.getStatus().equals(BorrowStatus.LOANING) || info.getStatus().equals(BorrowStatus.END))
		{
			if (info.getIsMakeRepayPlan().equals(BoolValue.NO) && info.getIsMakeReceivePlan().equals(BoolValue.YES))
			{
				getRepayPlans(info, plans);
				daoFactory.getRepaymentPlanDao().savePlans(plans);
				info.setLoanTime(new Date());
				info.setStatus(BorrowStatus.LOANING);
				info.setIsMakeRepayPlan(BoolValue.YES);
				daoFactory.getBorrowInfoDao().update(info);
			}
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void makeReceivePlans(BorrowInfo borrow)
	{
		BorrowInfo borrowInfo = daoFactory.getBorrowInfoDao().lockById(borrow.getId());
		if (borrow.getStatus().equals(BorrowStatus.LOANING) || borrow.getStatus().equals(BorrowStatus.END))
		{
			if (borrowInfo.getIsMakeReceivePlan().equals(BoolValue.NO))
			{
				List<InvestInfo> investList = daoFactory.getInvestInfoDao().queryList(borrow.getId(),
						new InvestStatus[] { InvestStatus.SUCESS, InvestStatus.LOANING });
				List<ReceivePlan> plans = new ArrayList<ReceivePlan>();
				for (InvestInfo invest : investList)
				{
					getRecPlans(borrow, invest, plans);
				}
				serviceFactory.getPersistService().saveAllObject(plans);
				borrowInfo.setIsMakeReceivePlan(BoolValue.YES);
				daoFactory.getBorrowInfoDao().update(borrowInfo);
			}
		}
	}

	/**
	 * <pre>
	 * 生成还款计划
	 * </pre>
	 * @param borrow
	 * @return
	 */
	private List<ReceivePlan> getRecPlans(BorrowInfo borrow, InvestInfo invest, List<ReceivePlan> plans)
	{
		long monthMoney = 0;
		switch (borrow.getRepaymentType())
		{
			case EQUALINTEREST:// 等额本息
				monthMoney = InvestUtils.equalInterest(invest.getInvestMoney(), borrow.getBorrowRate(),
						borrow.getBorrowDuration());// 月还款额

				long monthRewardMoney = InvestUtils.equalInterest(invest.getInvestMoney(),
						(borrow.getBorrowRate() + borrow.getRewardRate()), borrow.getBorrowDuration());// 加上附加利息的月收款总额

				Long[] monthBase = InvestUtils.equalInterestMonthBase(invest.getInvestMoney(), borrow.getBorrowRate(),
						borrow.getBorrowDuration());// 月还款本金

				for (int i = 0; i < monthBase.length; i++)
				{
					ReceivePlan plan = new ReceivePlan();
					plan.setBorrowInfoId(borrow.getId());
					plan.setBorrowName(borrow.getBorrowName());
					plan.setCurRecNum((i + 1));
					plan.setCreateTime(new Date());
					plan.setInvestmentInfoId(invest.getId());
					plan.setInvestUserId(invest.getInvestUserId());
					plan.setInvestUserName(invest.getInvestUserName());
					plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());

					plan.setRecBaseMoney(monthBase[i]);// 应收本金
					plan.setRecInterestMoney(monthMoney - monthBase[i]);// 应收利息
					plan.setRecMoney(monthRewardMoney);// 应收总金额
					plan.setRecAddMoney(monthRewardMoney - monthMoney);// 应收附加利息

					plan.setStatus(ReceiveStatus.WAITREC);
					plan.setTotalRecNum(monthBase.length);
					Date repayDate = StringUtils.addTime(new Date(), plan.getCurRecNum(), Calendar.MONTH);// 每期的最后还款日
					plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
					plans.add(plan);
				}
				break;
			case EQUALPRINCIPAL:// 等额本金
				Long[] monthInterest = InvestUtils.equalPrincipalMonthInterest(invest.getInvestMoney(),
						borrow.getBorrowRate(), borrow.getBorrowDuration());// 月收款利息
				Long[] monthAddInterest = InvestUtils.equalPrincipalMonthInterest(invest.getInvestMoney(),
						borrow.getRewardRate(), borrow.getBorrowDuration());// 月收款附加利息
				Long monthBaseMoney = InvestUtils.accuracy(invest.getInvestMoney() / borrow.getBorrowDuration());// 每月应还本金
				Long totalMoney = 0L;
				for (int i = 0; i < monthInterest.length; i++)
				{
					Long recBase = monthBaseMoney;
					if (i == monthInterest.length - 1)
					{
						recBase = invest.getInvestMoney() - totalMoney;
					}
					else
					{
						totalMoney = totalMoney + recBase;
					}
					ReceivePlan plan = new ReceivePlan();
					plan.setBorrowInfoId(borrow.getId());
					plan.setBorrowName(borrow.getBorrowName());
					plan.setCurRecNum((i + 1));
					plan.setCreateTime(new Date());
					plan.setInvestmentInfoId(invest.getId());
					plan.setInvestUserId(invest.getInvestUserId());
					plan.setInvestUserName(invest.getInvestUserName());
					plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());
					plan.setRecBaseMoney(recBase);
					plan.setRecInterestMoney(monthInterest[i]);
					plan.setRecAddMoney(monthAddInterest[i]);// 应收附加利息
					plan.setRecMoney(recBase + monthInterest[i] + monthAddInterest[i]);
					plan.setStatus(ReceiveStatus.WAITREC);
					plan.setTotalRecNum(monthInterest.length);
					Date repayDate = StringUtils.addTime(new Date(), plan.getCurRecNum(), Calendar.MONTH);// 每期的最后还款日
					plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
					plans.add(plan);
				}
				break;
			case MONTHINTEREST:// 月付息
				for (int i = 1; i <= borrow.getBorrowDuration(); i++)
				{
					ReceivePlan plan = new ReceivePlan();
					plan.setBorrowInfoId(borrow.getId());
					plan.setBorrowName(borrow.getBorrowName());
					plan.setCurRecNum(i);
					plan.setCreateTime(new Date());
					plan.setInvestmentInfoId(invest.getId());
					plan.setInvestUserId(invest.getInvestUserId());
					plan.setInvestUserName(invest.getInvestUserName());
					plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());

					long interest = InvestUtils.rtcapitalMonthInterest(invest.getInvestMoney(), borrow.getBorrowRate(),
							borrow.getDurType());// 每月应还利息相等
					long add = InvestUtils.rtcapitalMonthInterest(invest.getInvestMoney(), borrow.getRewardRate(),
							borrow.getDurType());// 每月应还附加利息
					plan.setRecBaseMoney(0L);
					if (i == borrow.getBorrowDuration())
					{
						plan.setRecBaseMoney(invest.getInvestMoney());
					}
					plan.setRecMoney(plan.getRecBaseMoney() + interest + add);// 应还总金额
					plan.setRecInterestMoney(interest);// 应还利息
					plan.setRecAddMoney(add);// 附加利息

					plan.setStatus(ReceiveStatus.WAITREC);
					plan.setTotalRecNum(borrow.getBorrowDuration());
					Date repayDate = StringUtils.addTime(new Date(), plan.getCurRecNum(), Calendar.MONTH);// 每期的最后还款日
					plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
					plans.add(plan);
				}
				break;
			case RTCAPITALINTEREST:// 一次付
				ReceivePlan plan = new ReceivePlan();
				plan.setBorrowInfoId(borrow.getId());
				plan.setBorrowName(borrow.getBorrowName());
				plan.setCurRecNum(1);
				plan.setCreateTime(new Date());
				plan.setInvestmentInfoId(invest.getId());
				plan.setInvestUserId(invest.getInvestUserId());
				plan.setInvestUserName(invest.getInvestUserName());
				plan.setInvestUserTrustAccountId(invest.getInvestUserTrustAccountId());
				long interest = InvestUtils.rtcapitalInterest(invest.getInvestMoney(), borrow.getBorrowRate(),
						borrow.getBorrowDuration(), borrow.getDurType());
				long add = InvestUtils.rtcapitalInterest(invest.getInvestMoney(), borrow.getRewardRate(),
						borrow.getBorrowDuration(), borrow.getDurType());// 附加利息
				plan.setRecBaseMoney(invest.getInvestMoney());
				plan.setRecAddMoney(add);// 附加利息
				plan.setRecInterestMoney(interest);// 应还利息
				plan.setRecMoney(invest.getInvestMoney() + interest + add);// 应还总金额
				plan.setStatus(ReceiveStatus.WAITREC);
				plan.setTotalRecNum(1);
				int type = Calendar.MONTH;
				if (!borrow.getDurType().equals(DurationType.MONTH))
				{
					type = Calendar.DATE;
				}
				Date repayDate = StringUtils.addTime(new Date(), borrow.getBorrowDuration(), type);// 每期的最后还款日
				plan.setArrivalTime(DateTimeUtil.getSomeDayStartTimes(repayDate));
				plans.add(plan);
				break;
		}
		return plans;
	}

	/**
	 * <pre>
	 * 生成还款计划
	 * </pre>
	 * @param borrow
	 * @return
	 */
	private void getRepayPlans(BorrowInfo borrow, List<RepaymentPlan> plans)
	{
		List<ReceivePlan> planList = daoFactory.getStaticJDBCDao().getTotleList(borrow.getId());
		for (ReceivePlan receivePlan : planList)
		{
			RepaymentPlan plan = new RepaymentPlan();
			plan.setBorrowInfoId(borrow.getId());
			plan.setBorrowName(borrow.getBorrowName());
			plan.setBorrowUserId(borrow.getBorrowUserId());
			plan.setBorrowUserName(borrow.getBorrowUserName());
			plan.setCreateTime(new Date());
			plan.setCurRepayNum(receivePlan.getCurRecNum());
			plan.setIsOverDured(BoolValue.NO);
			plan.setLastRepayDate(receivePlan.getArrivalTime());
			plan.setOverdueDate(DateTimeUtil.addDate(plan.getLastRepayDate(), 1));// 逾期起息日，为最后还款日的下一天
			plan.setOverduePenalty(0L);
			plan.setRepayAddMoney(receivePlan.getRecAddMoney());// 应还附加利息(由平台账户付款)
			plan.setRepayBaseMoney(receivePlan.getRecBaseMoney());// 应还本金
			plan.setRepayMoney(receivePlan.getRecMoney());// 应还总金额
			plan.setRepayInterestMoney(receivePlan.getRecInterestMoney());// 应还利息
			plan.setStatus(ReplaymentStatus.UNSETTLE);
			plan.setTotalRepayNum(receivePlan.getTotalRecNum());
			plans.add(plan);
		}
	}

	/**
	 * <pre>
	 * 标的信息录入
	 * </pre>
	 * @param request
	 */
	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public ResponseMessage addBidInfo(RequestMessage request)
	{
		ResponseMessage response = null;
		AddBidInfoRequest addRequest = (AddBidInfoRequest) request;
		Long borowId = Long.parseLong(addRequest.getProId());
		BorrowInfo borrow = daoFactory.getBorrowInfoDao().lockInfo(borowId);
		if (borrow != null)
		{
			if (borrow.getInputStatus() == InputStatus.WAIT || borrow.getInputStatus() == InputStatus.FAILED)
			{
				response = serviceFactory.getPartnerService().request(request);
				if (CommonCode.TRANS_SUC.equals(response.getRespCode())
						|| BorrowInfoCode.TRANSMESSAGE_ERRCODE_ADDBID_EXIST.equals(response.getRespCode()))
				{
					borrow.setInputStatus(InputStatus.SUCCESS);
				}
				else
				{
					borrow.setInputStatus(InputStatus.FAILED);
				}
				daoFactory.getBorrowInfoDao().updateInfo(borrow);
			}
		}
		return response;
	}

	@Override
	public void borrowLoanEnd()
	{
		List<BorrowInfo> list = daoFactory.getBorrowInfoDao().queryBorrowList(BorrowStatus.LOANING);
		for (BorrowInfo borrowInfo : list)
		{
			serviceFactory.getBorrowService().requireNewLoanEnd(borrowInfo);
		}
	}

	@Override
	public void borrowLossEnd()
	{
		List<BorrowInfo> list = daoFactory.getBorrowInfoDao().queryBorrowList(BorrowStatus.LOSSING);
		for (BorrowInfo borrowInfo : list)
		{
			serviceFactory.getBorrowService().requireNewLoanEnd(borrowInfo);
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void requireNewLossEnd(BorrowInfo borrowInfo)
	{
		BorrowInfo borrow = daoFactory.getBorrowInfoDao().lockById(borrowInfo.getId());
		if (borrow.getStatus().equals(BorrowStatus.LOANING))
		{
			InvestStatus[] status = new InvestStatus[] { InvestStatus.CANCLED, InvestStatus.SUCESS,
					InvestStatus.CANCLING };
			long count = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(), status);
			long cancled = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(),
					new InvestStatus[] { InvestStatus.CANCLED });
			if (count == cancled)
			{
				borrow.setStatus(BorrowStatus.LOSSED);
			}
			daoFactory.getBorrowInfoDao().update(borrow);
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void requireNewLoanEnd(BorrowInfo borrowInfo)
	{
		BorrowInfo borrow = daoFactory.getBorrowInfoDao().lockById(borrowInfo.getId());
		if (borrow.getStatus().equals(BorrowStatus.LOANING))
		{
			InvestStatus[] status = new InvestStatus[] { InvestStatus.LOANED, InvestStatus.SUCESS, InvestStatus.LOANING };
			long count = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(), status);
			long loaned = daoFactory.getInvestInfoDao().countByBorrowId(borrow.getId(),
					new InvestStatus[] { InvestStatus.LOANED });
			if (count == loaned)
			{
				if (!serviceFactory.getPartnerService().isTrustPattern())
				{
					RepaymentPlan plan = daoFactory.getStaticJDBCDao().getTotleRepay(borrow.getId());
					Long repayBaseMoney = plan.getRepayBaseMoney();
					Long repayInterestMoney = plan.getRepayInterestMoney();
					if (borrow.getRaiseMoney().longValue() == repayBaseMoney)
					{
						Long guaFee = InvestUtils.accuracy(repayBaseMoney * borrow.getGuaranteeFeeRate() / 100);// 保证金费率
						Long fee = InvestUtils.accuracy(repayBaseMoney * borrow.getBorrowFeeRate() / 100);// 平台佣金

						serviceFactory.getAccountService().loansChangeAccountMoney(borrow.getBorrowUserId(),
								repayBaseMoney, repayBaseMoney, repayInterestMoney, TransType.LOAN, TradeMode.ADD,
								borrow.getId().toString(), "标的借款放款收入:" + borrow.getBorrowName(), true);// 借款人收入借款金额

						serviceFactory.getAccountService().subtractNoFreeze(borrow.getBorrowUserId(),
								TransType.LOAN_GUAR, guaFee, borrow.getId().toString(),
								"标的放款保证金费用扣款:" + borrow.getBorrowName());// 借款用户扣除保证金

						serviceFactory.getAccountService().subtractNoFreeze(borrow.getBorrowUserId(),
								TransType.LOAN_FEE, fee, borrow.getId().toString(),
								"标的放款服务费扣款:" + borrow.getBorrowName());// 借款用户扣服务费证金

						serviceFactory.getAccountService().add(borrow.getGuaranteeUserId(), TransType.LOAN_GUAR,
								guaFee, borrow.getId().toString(), "标的保证金放款收入:" + borrow.getBorrowName());// 保证金账户加担保费用

						borrow.setStatus(BorrowStatus.REPAYMENTING);
					}
					else
					{
						logger.error("更新标的状态异常，还款计划总金额与募集资金不一致，标的:" + borrow.getId() + ",募集：" + borrow.getRaiseMoney()
								+ ",待还金额:" + repayBaseMoney);
					}
				}
				else
				{
					borrow.setStatus(BorrowStatus.REPAYMENTING);
				}
			}
			daoFactory.getBorrowInfoDao().update(borrow);
		}
	}

	@Override
	public void loansReconciliation(Integer pageNum, Integer pageSize, Date beginDate, Date endDate)
	{
		ReconciliationResponseMsg response = serviceFactory.getBorrowService().doLoansReconciliation(pageNum, pageSize,
				beginDate, endDate);
		if (!StringHelper.isEmpty(response.getTotalItems())
				&& (pageNum * pageSize) < Integer.parseInt(response.getTotalItems()))
		{
			loansReconciliation(pageNum + 1, pageSize, beginDate, endDate);
		}
	}

	@Override
	public ReconciliationResponseMsg doLoansReconciliation(Integer pageNum, Integer pageSize, Date beginDate,
			Date endDate)
	{
		ReconciliationRequestMsg reqMsg = new ReconciliationRequestMsg();
		reqMsg.setBeginDate(DateTimeUtil.formatToStr(beginDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
		reqMsg.setEndDate(DateTimeUtil.formatToStr(endDate, DateTimeUtil.DATE_FORMAT_YYYYMMDD));
		reqMsg.setPageNum(pageNum.toString());
		reqMsg.setPageSize(pageSize.toString());
		reqMsg.setQueryTransType("LOANS");
		reqMsg.setPartnerTransType(PartnerTransType.Reconciliation);
		reqMsg.setTransType(TransCodeConstants.PartnerTransCode.REQUEST);
		ReconciliationResponseMsg response = (ReconciliationResponseMsg) serviceFactory.getPartnerService().request(
				reqMsg);
		List<ReconciliationInfo> list = response.getReconciliationDtoList();
		if (list != null && list.size() > 0)
		{
			for (ReconciliationInfo dto : list)
			{
				final LoansResponse loansResponse = new LoansResponse();
				loansResponse.setOrdId(dto.getOrdId());
				if ("I".equals(dto.getTransStat()))
				{// 失败
					loansResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_FAIL);
					loansResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_FAIL_MSG);
				}
				else if ("P".equals(dto.getTransStat()))
				{// 成功
					loansResponse.setRespCode(RespCodeConstants.CommonCode.TRANS_SUC);
					loansResponse.setRespDesc(RespCodeConstants.CommonCode.TRANS_SUC_MSG);
				}
				execute.execute(new Runnable()
				{
					@Override
					public void run()
					{
						serviceFactory.getBorrowService().loansResponse(loansResponse);
					}
				});
			}
		}
		return response;
	}
}